package com.panopset.gui;

import static com.panopset.Util.x;

import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.WindowConstants;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import com.panopset.java.Version;
import com.panopset.swing.FontManager;
import java.util.ArrayList;

/**
 * Standard panel with a white background. Can be titled.
 *
 * @author Karl Dinwiddie
 *
 */
public class TPanel extends JPanel implements WindowConstants {

    /**
     * Titled border required.
     */
    private TitledBorder titledBorderRequired;

    /**
     * Titled border.
     */
    private TitledBorder titledBorder;

    /**
     * Border title.
     */
    private String borderTitle = "";

    /**
     * Border color.
     */
    private Color borderColor = LookAndFeel.Colors.BORDER_COLOR_NORMAL
            .getColor();

    /**
     * Standard border insets are 2, 4, 2, 4.
     */
    public static final Insets STANDARD_BORDER_INSETS = new Insets(2, 4, 2, 4);

    /**
     * @return New line border.
     */
    public static final LineBorder createLineBorder() {
        return createLineBorder(null, 1);
    }

    /**
     * Create line border.
     *
     * @param color
     *            Color.
     * @param thickness
     *            Thickness.
     * @return Line border.
     */
    public static final LineBorder createLineBorder(final Color color,
            final int thickness) {
        Color clr = color;
        if (color == null) {
            clr = LookAndFeel.Colors.BORDER_COLOR_NORMAL.getColor();
        }
        return new LineBorder(clr, thickness, true) {

            /**
             * Border insets top=2,left=4,bottom=2,right=4.
             *
             * @param Component
             */
            @Override
            public Insets getBorderInsets(final Component c) {
                return STANDARD_BORDER_INSETS;
            }

            /**
             * Serial version number.
             */
            private static final long serialVersionUID = Version.UNI_VERSION;
        };
    }

    /**
     * Required prompt.
     */
    private String requiredPrompt;

    /**
     * @return Prompt when a required field needs to be entered.
     */
    public final String getRequiredPrompt() {
        if (requiredPrompt == null) {
            requiredPrompt = x("required");
        }
        return requiredPrompt;
    }

    /**
     * @return Titled border on a required field that needs to be populated.
     */
    public final TitledBorder getTitledBorderRequired() {
        if (titledBorderRequired == null) {
            titledBorderRequired = new TitledBorder(createLineBorder(Color.RED,
                    2), borderTitle + " (" + getRequiredPrompt() + ")");
            FontManager.register(titledBorderRequired,
                    FontManager.FontType.borderTitle);
        }
        return titledBorderRequired;
    }

    /**
     * @return Normal titled border.
     */
    public final TitledBorder getTitledBorder() {
        if (titledBorder == null) {
            titledBorder = new TitledBorder(createLineBorder(borderColor, 1),
                    borderTitle);
            FontManager.register(titledBorder,
                    FontManager.FontType.borderTitle);
        }
        return titledBorder;
    }

    /**
     * Set the titled border to normal.
     */
    public final void setNormalBorder() {
        setBorder(getTitledBorder());
    }

    /**
     * Set the titled border to required, prompting an entry.
     */
    public final void setRequiredBorder() {
        setBorder(getTitledBorderRequired());
    }

    /**
     * Create the border.
     */
    private void createBorder() {
        setBorder(getTitledBorder());
    }

    /**
     * Builder.
     */
    public static final class Builder {

        /**
         * Border title.
         */
        private String borderTitle;

        /**
         * Tool tip text.
         */
        private String tip;

        /**
         * Name.
         */
        private String name;

        /**
         * Required prompt.
         */
        private String requiredPrompt;

        /**
         * Layout manager.
         */
        private LayoutManager layout;

        /**
         * Background.
         */
        private Color background;

        /**
         * Border color.
         */
        private Color borderColor;

        /**
         * Components to add.
         */
        private final List<Component> adds = new ArrayList<Component>();

        /**
         * @return Panel.
         */
        public TPanel construct() {
            TPanel rtn = new TPanel();
            if (name != null) {
                rtn.setName(name);
            }
            if (layout == null) {
                rtn.setLayout(new FlowLayout());
            } else {
                rtn.setLayout(layout);
            }
            if (background != null) {
                rtn.setBackground(background);
            }
            if (tip != null) {
                rtn.setToolTipText(tip);
            }
            for (Component c : adds) {
                rtn.add(c);
            }
            if (borderTitle == null && borderColor == null) {
                return rtn;
            }
            if (borderTitle != null) {
                rtn.borderTitle = borderTitle;
            }
            if (borderColor != null) {
                rtn.borderColor = borderColor;
            }
            if (requiredPrompt != null) {
                rtn.requiredPrompt = requiredPrompt;
            }
            rtn.createBorder();
            return rtn;
        }

        /**
         * Add a component to the panel.
         *
         * @param comp
         *            Component to add.
         * @return Builder.
         */
        public Builder add(final Component comp) {
            adds.add(comp);
            return this;
        }

        /**
         * Assign a border color. If no title is specified, this method may be
         * used to create a border.
         *
         * @param value
         *            Border color.
         * @return Builder.
         */
        public Builder borderColor(final Color value) {
            this.borderColor = value;
            return this;
        }

        /**
         * Assign a border and title. If no borderColor is specified, default is
         * dark red.
         *
         * @param value
         *            Border title.
         * @return Builder.
         */
        public Builder borderTitle(final String value) {
            borderTitle = value;
            return this;
        }

        /**
         * Tool tip text.
         *
         * @param value
         *            Tip text.
         * @return Builder.
         */
        public Builder tip(final String value) {
            tip = value;
            return this;
        }

        /**
         * Assign a background color, default is white.
         *
         * @param value
         *            Background color.
         * @return Builder.
         */
        public Builder background(final Color value) {
            background = value;
            return this;
        }

        /**
         * If no LayoutManager is specified, GridLayout(1,1) will be used.
         *
         * @param value
         *            Layout.
         * @return Builder.
         */
        public Builder layout(final LayoutManager value) {
            layout = value;
            return this;
        }

        /**
         * Assign a name to the component, which will show up in a tabbed pane
         * tab.
         *
         * @param value
         *            Component name.
         * @return Builder.
         */
        public Builder name(final String value) {
            name = value;
            return this;
        }

        /**
         * Default is &quot;required&quot;. Change it to something more
         * meaningful with this method.
         *
         * @param value
         *            Required prompt.
         * @return Builder.
         */
        public Builder requiredPrompt(final String value) {
            this.requiredPrompt = value;
            return this;
        }
    }

    /**
     * Creates a TPanel with a FlowLayout layout.
     */
    public TPanel() {
        this(new FlowLayout());
    }

    /**
     * @param mgr
     *            Layout manager.
     */
    public TPanel(final LayoutManager mgr) {
        super(mgr);
        setBackground(LookAndFeel.Colors.BG_COLOR.getColor());
    }

    /**
     * Serial version id.
     */
    private static final long serialVersionUID = Version.UNI_VERSION;
}
